// 提前连接上wifi
// 需要在menuconfig里面搜索tls，然后打开下面两个，防止证书验证
// Allow potentially insecure options
// Skip server certificate verification by default (WARNING: ONLY FOR TESTING PURPOSE, READ HELP)

// weather_init("SPX7mUNmWYAkOZZ9G", "beijing");
// while (1)
// {
//     weather_updata();
//     printf("%s\n", weather_name_get());
//     printf("%s\n", weather_country_get());
//     printf("%s\n", weather_text_get());
//     printf("%s\n", weather_temperature_get());
//     printf("%s\n", weather_last_update_get());
//     vTaskDelay(10000 / portTICK_PERIOD_MS);
// }

#include <string.h>
#include <sys/param.h>
#include <stdlib.h>
#include <ctype.h>
#include "esp_log.h"
#include "esp_err.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"

#include "esp_http_client.h"
#include "cJSON.h"

// 心知天气免费只能获取location的内容和new里面的text和temperature
typedef struct
{
    char my_location[12];
    char my_key[18];
    // char id;
    char name[18];
    char country[18];
    // char path;
    // char timezone;
    // char timezone_offset;
    char text[12];       // 天气现象文字
    char temperature[4]; // 温度，单位为c摄氏度或f华氏度
    // char feels_like;            // 体感温度，单位为c摄氏度或f华氏度
    // char pressure;              // 气压，单位为mb百帕或in英寸
    // char humidity;              // 相对湿度，0~100，单位为百分比
    // char visibility;            // 能见度，单位为km公里或mi英里
    // char wind_direction;        // 风向文字
    // char wind_direction_degree; // 风向角度，范围0~360，0为正北，90为正东，180为正南，270为正西
    // char wind_speed;            // 风速，单位为km/h公里每小时或mph英里每小时
    // char wind_scale;            // 风力等级
    // char clouds;                // 云量，单位%，范围0~100，天空被云覆盖的百分比
    // char dew_point;             // 露点温度
    char last_update[128];
} weather_data_t;

weather_data_t weather_data;

static const char *TAG = "Weather data get";

static void parse_weather_data(const char *json);
static esp_err_t weahter_event_handler(esp_http_client_event_t *evt);
void weather_init(const char *key, const char *location);
void weather_updata(void);
char *weather_name_get(void);
char *weather_country_get(void);
char *weather_text_get(void);
char *weather_temperature_get(void);
char *weather_last_update_get(void);

// {
//     "results" : [
//         {
//             "location" : {
//                 "id" : "C23NB62W20TF",
//                 "name" : "西雅图",
//                 "country" : "US",
//                 "path" : "西雅图,华盛顿州,美国",
//                 "timezone" : "America/Los_Angeles",
//                 "timezone_offset" : "-07:00"
//             },
//             "now" : {
//                 "text" : "多云",                 // 天气现象文字
//                 "code" : "4",                    // 天气现象代码
//                 "temperature" : "14",            // 温度，单位为c摄氏度或f华氏度
//                 "feels_like" : "14",             // 体感温度，单位为c摄氏度或f华氏度
//                 "pressure" : "1018",             // 气压，单位为mb百帕或in英寸
//                 "humidity" : "76",               // 相对湿度，0~100，单位为百分比
//                 "visibility" : "16.09",          // 能见度，单位为km公里或mi英里
//                 "wind_direction" : "西北",       // 风向文字
//                 "wind_direction_degree" : "340", // 风向角度，范围0~360，0为正北，90为正东，180为正南，270为正西
//                 "wind_speed" : "8.05",           // 风速，单位为km/h公里每小时或mph英里每小时
//                 "wind_scale" : "2",              // 风力等级，请参考：http://baike.baidu.com/view/465076.htm
//                 "clouds" : "90",                 // 云量，单位%，范围0~100，天空被云覆盖的百分比 #目前不支持中国城市#
//                 "dew_point" : "-12"              // 露点温度，请参考：http://baike.baidu.com/view/118348.htm #目前不支持中国城市#
//             },
//             "last_update" : "2015-09-25T22:45:00-07:00" // 数据更新时间（该城市的本地时间）
//         }
//     ]
// }

static void parse_weather_data(const char *json)
{
    cJSON *root = cJSON_Parse(json);
    if (root == NULL)
    {
        ESP_LOGI(TAG, "Failed to parse JSON!");
        return;
    }
    cJSON *result = cJSON_GetObjectItem(root, "results");
    if (result != NULL && cJSON_IsArray(result))
    {
        cJSON *location = cJSON_GetObjectItem(result->child, "location");
        if (location != NULL && cJSON_IsObject(location))
        {
            cJSON *name = cJSON_GetObjectItem(location, "name");
            if (name != NULL && cJSON_IsString(name))
            {
                sprintf(weather_data.name, "%s", name->valuestring);
            }

            cJSON *country = cJSON_GetObjectItem(location, "country");
            if (country != NULL && cJSON_IsString(country))
            {
                sprintf(weather_data.country, "%s", country->valuestring);
            }
        }

        cJSON *now = cJSON_GetObjectItem(result->child, "now");
        if (now != NULL && cJSON_IsObject(now))
        {
            cJSON *text = cJSON_GetObjectItem(now, "text");
            if (text != NULL && cJSON_IsString(text))
            {
                sprintf(weather_data.text, "%s", text->valuestring);
            }

            cJSON *temperature = cJSON_GetObjectItem(now, "temperature");
            if (temperature != NULL && cJSON_IsString(temperature))
            {
                sprintf(weather_data.temperature, "%s", temperature->valuestring);
            }
        }

        cJSON *last_update = cJSON_GetObjectItem(result->child, "last_update");
        if (last_update != NULL)
        {
            sprintf(weather_data.last_update, "%s", last_update->valuestring);
        }
    }
    cJSON_Delete(root);
}

static esp_err_t weahter_event_handler(esp_http_client_event_t *evt)
{
    switch (evt->event_id)
    {
    case HTTP_EVENT_ERROR:
        ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
        break;
    case HTTP_EVENT_ON_CONNECTED:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
        break;
    case HTTP_EVENT_HEADER_SENT:
        ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
        break;
    case HTTP_EVENT_ON_HEADER:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
        break;
    case HTTP_EVENT_ON_DATA:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
        /*
         *  Check for chunked encoding is added as the URL for chunked encoding used in this example returns binary data.
         *  However, event handler can also be used in case chunked encoding is used.
         */
        if (!esp_http_client_is_chunked_response(evt->client))
        {
            parse_weather_data(evt->data);
        }
        break;
    case HTTP_EVENT_ON_FINISH:
        break;
    case HTTP_EVENT_DISCONNECTED:
        break;
    case HTTP_EVENT_REDIRECT:
        break;
    }
    return ESP_OK;
}

void weather_init(const char *key, const char *location)
{
    memset(&weather_data, 0, sizeof(weather_data));
    strcpy(weather_data.my_key, key);
    strcpy(weather_data.my_location, location);
}

void weather_updata(void)
{
    esp_http_client_config_t config = {
        .method = HTTP_METHOD_GET,
        .url = "https://api.seniverse.com/v3/weather/now.json",
        .event_handler = weahter_event_handler,
        .skip_cert_common_name_check = true,
    };

    char url[256];
    sprintf(url, "%s?key=%s&location=%s&language=zh-Hans&unit=c", config.url, weather_data.my_key, weather_data.my_location);
    config.url = url;

    esp_http_client_handle_t client = esp_http_client_init(&config);
    esp_err_t err = esp_http_client_perform(client);

    if (err == ESP_OK)
    {
        ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %" PRIu64,
                 esp_http_client_get_status_code(client),
                 esp_http_client_get_content_length(client));
    }
    else
    {
        ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
    }
    esp_http_client_cleanup(client);
}

char *weather_name_get(void)
{
    return weather_data.name;
}

char *weather_country_get(void)
{
    return weather_data.country;
}

char *weather_text_get(void)
{
    return weather_data.text;
}

char *weather_temperature_get(void)
{
    return weather_data.temperature;
}

char *weather_last_update_get(void)
{
    return weather_data.last_update;
}